//
//  UITextView+HBTextLength.m
//  HBLibary
//
//  Created by Rambo on 2018/6/8.
//

#import "UITextView+HBTextLength.h"
#import "NSObject+HBCategory.h"
#import <objc/runtime.h>
#import "NSString+HBCategory.h"

static void *kMaxLengthKey = &kMaxLengthKey;
static void *kTextLengthChangeKey = &kTextLengthChangeKey;
static void *kPlaceholderLabelKey = &kPlaceholderLabelKey;
static void *kPlaceholderKey = &kPlaceholderKey;
static void *kPlaceholderColorKey = &kPlaceholderColorKey;
static void *kTextCountLabelKey = &kTextCountLabelKey;
static void *kShowTextCountKey = &kShowTextCountKey;
static void *kTextCountDefaultColorKey = &kTextCountDefaultColorKey;
static void *kTextCountFullColorKey = &kTextCountFullColorKey;
static void *kCurrentTextCountKey = &kCurrentTextCountKey;
static void *kTextCountFontKey = &kTextCountFontKey;
static void *kTextCountRightMarginKey = &kTextCountRightMarginKey;
static void *kTextCountBottomMarginKey = &kTextCountBottomMarginKey;
static void *kAutoInterceptMaxLentghKey = &kAutoInterceptMaxLentghKey;

static CGFloat const kPlaceholderHorizontalMargin = 5;
static CGFloat const kPlaceholderVerticalMarigin = 8;

@interface UITextView ()

@property (nonatomic, strong) UILabel *placeholderLabel;

@property (nonatomic, strong) UILabel *textCountLabel;

@property (nonatomic, assign) NSUInteger currentTextCount;

@property (nonatomic, assign) BOOL isInit;

@end

@implementation UITextView (HBTextLength)


+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [NSObject hb_swizzlingInstanceMethodWithClass:self originSel:@selector(initWithFrame:) newSel:@selector(TextLength_initWithFrame:)];
        [NSObject hb_swizzlingInstanceMethodWithClass:self originSel:@selector(removeFromSuperview) newSel:@selector(TextLength_removeFromSuperview)];
        [NSObject hb_swizzlingInstanceMethodWithClass:self originSel:@selector(layoutSubviews) newSel:@selector(TextLength_layoutSubviews)];
        [NSObject hb_swizzlingInstanceMethodWithClass:self originSel:@selector(initWithCoder:) newSel:@selector(TextLength_initWithCoder:)];
        [NSObject hb_swizzlingInstanceMethodWithClass:self originSel:NSSelectorFromString(@"dealloc") newSel:@selector(TextLength_dealloc)];
    });
}

#pragma mark - ------------swizzling method-------------

- (void)TextLength_layoutSubviews{
    [self TextLength_layoutSubviews];
    
    //计算 placeholderLabel frame
    if (![self.hb_placeholder isEqualToString:self.placeholderLabel.text] ||
        ((CGRectGetWidth(self.placeholderLabel.frame) + 2*kPlaceholderHorizontalMargin) != CGRectGetWidth(self.frame))) {
        CGFloat maxWidth = CGRectGetWidth(self.frame) - 2*kPlaceholderHorizontalMargin;
        CGFloat maxHeight = CGRectGetHeight(self.frame) - 2*kPlaceholderVerticalMarigin;
        CGSize maxSize = CGSizeMake(maxWidth, maxHeight);
        self.placeholderLabel.font = self.font;
        self.placeholderLabel.textColor = self.hb_placeholderColor;
        self.placeholderLabel.text = self.hb_placeholder;
        CGSize placeholderSize = [self textSizeWithText:self.hb_placeholder maxSize:maxSize];
        self.placeholderLabel.frame = CGRectMake(kPlaceholderHorizontalMargin, kPlaceholderVerticalMarigin, placeholderSize.width, placeholderSize.height);
    }
    
    //计算 textCountLabel frame
    if (!self.showTextCount) return;
    
    if ( ((CGRectGetWidth(self.textCountLabel.frame) + 2*self.textCountRightMargin) != CGRectGetWidth(self.frame))) {
        CGRect rect = self.textCountLabel.frame;
        rect.size.width = CGRectGetWidth(self.frame) - 2*self.textCountRightMargin;
        rect.origin.x = self.textCountRightMargin;
        rect.size.height = self.textCountFont.ascender - self.textCountFont.descender;
        self.textCountLabel.frame = rect;
    }
    
    CGRect rect = self.textCountLabel.frame;
    rect.origin.y = CGRectGetHeight(self.frame) - self.textCountBottomMargin - rect.size.height + self.contentOffset.y;
    self.textCountLabel.frame = rect;
    
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    
//    if (self.placeholderLabel.isHidden) return;
    if (self != object) return;
    if (![keyPath isEqualToString:@"text"]) return;
    
    UITextRange *textRange = self.markedTextRange;
    UITextPosition *position = [self positionFromPosition:textRange.start offset:0];
    if (position && textRange) return;
    
    NSString *newText = change[@"new"];
    NSString *oldText = change[@"old"];
    if ([newText isEqualToString:oldText]) return;
    [self TextChange_Edit];
}

- (instancetype)TextLength_initWithCoder:(NSCoder *)aDecoder{
    UITextView *textView = [self TextLength_initWithCoder:aDecoder];
    [self initSubview];
    return textView;
}

- (instancetype)TextLength_initWithFrame:(CGRect)frame{
    UITextView *textView = [self TextLength_initWithFrame:frame];
    [self initSubview];
    return textView;
}

- (void)TextLength_removeFromSuperview{
    
    [self TextLength_removeFromSuperview];
}

- (void)TextLength_dealloc{
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    if (self.isInit) [self removeObserver:self forKeyPath:@"text"];
    [self TextLength_dealloc];
}

#pragma mark - -----------------通知-------------------

- (void)textChange:(NSNotification*)notify{
    id objc = notify.object;
    if (self != objc) return;
    
    [self TextChange_Edit];
}

#pragma mark - ------------ private method-------------

- (void)initSubview{
    objc_setAssociatedObject(self, kTextCountFontKey, [UIFont systemFontOfSize:12], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    objc_setAssociatedObject(self, kTextCountDefaultColorKey, [[UIColor darkGrayColor] colorWithAlphaComponent:0.5], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    objc_setAssociatedObject(self, kTextCountFullColorKey, [UIColor redColor], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    objc_setAssociatedObject(self, kPlaceholderColorKey, [[UIColor darkGrayColor] colorWithAlphaComponent:0.5], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    objc_setAssociatedObject(self, kShowTextCountKey, @(NO), OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, kMaxLengthKey, @(0), OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, kTextCountRightMarginKey, @(0), OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, kTextCountBottomMarginKey, @(0), OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, kCurrentTextCountKey, @(0), OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, kAutoInterceptMaxLentghKey, @(NO), OBJC_ASSOCIATION_COPY_NONATOMIC);
    self.font = [UIFont systemFontOfSize:[UIFont systemFontSize]];
    //    self.textCountFont = [UIFont systemFontOfSize:12];
    //    self.textCountDefaultColor = [[UIColor darkGrayColor] colorWithAlphaComponent:0.5];
    //    self.textCountFullColor = [UIColor redColor];
    //    self.placeholderColor = [[UIColor darkGrayColor] colorWithAlphaComponent:0.5];
    //    self.showTextCount = NO;
    //    _textCountRightMargin = 0;
    //    _textCountBottomMargin = 0;
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange:) name:UITextViewTextDidChangeNotification object:self];
    [self addObserver:self forKeyPath:@"text" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:nil];
    self.isInit = true;
}

- (void)TextChange_Edit{
    
    self.placeholderLabel.hidden = self.hasText;
//    NSLog(@"%@----%d",self, self.hasText);
    
    //预选编辑（高亮部分）
    UITextRange *textRange = self.markedTextRange;
    UITextPosition *position = [self positionFromPosition:textRange.start offset:0];
    //    NSLog(@"%@---%@",position, textRange);
    
    if (position && textRange) return;
    
    NSString *toBeString = self.text;
    //统计字符总长度（符號、字母、數字、漢字均算為1字元）
    NSRange range = NSMakeRange(0, 0);
    NSInteger textLength = 0;
    NSUInteger interceptTextMaxLength = 0;
    for (NSInteger idx = 0; idx < toBeString.length; ) {
        if (self.hb_maxLength > 0 && textLength <= self.hb_maxLength) {
            interceptTextMaxLength += range.length;
        }
        range = [toBeString rangeOfComposedCharacterSequenceAtIndex:idx];
        idx += range.length;

        textLength += range.length;  //+=1

        
    }
    
    
    if (self.hb_autoInterceptMaxLength && self.hb_maxLength > 0 && textLength > self.hb_maxLength && interceptTextMaxLength <= self.text.length) {
        self.text = [toBeString substringToIndex:interceptTextMaxLength];
//        textLength = self.hb_maxLength;
        textLength = self.text.length;
    }
    
    
    if (self.hb_textLengthChange) {
        self.hb_textLengthChange(textLength, self.hb_maxLength);
    }
    
    self.currentTextCount = textLength;
    [self updateTextCountProperty];
    
}

- (CGSize)textSizeWithText:(NSString*)text maxSize:(CGSize)maxSize{
    if ([NSString hb_isEmpty:text]) {
        return CGSizeZero;
    }
    return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName : self.font} context:nil].size;
}

- (void)updateTextCountProperty{
    if (!self.showTextCount) return;
    self.textCountLabel.text = [NSString stringWithFormat:@"%zd/%zd",self.currentTextCount, self.hb_maxLength];
    self.textCountLabel.textColor = self.currentTextCount > self.hb_maxLength ? self.textCountFullColor : self.textCountDefaultColor;
}

#pragma mark - -----property---------

#pragma mark - **maxLength

- (void)setHb_maxLength:(NSUInteger)hb_maxLength{
    objc_setAssociatedObject(self, kMaxLengthKey, @(hb_maxLength), OBJC_ASSOCIATION_COPY_NONATOMIC);
    [self updateTextCountProperty];
}

- (NSUInteger)hb_maxLength{
    NSNumber *number = objc_getAssociatedObject(self, kMaxLengthKey);
    return [number unsignedIntegerValue];
}

#pragma mark - **textLengthChange

- (void)setHb_textLengthChange:(UITextViewTextLengthChangeBlock)hb_textLengthChange{
    objc_setAssociatedObject(self, kTextLengthChangeKey, hb_textLengthChange, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (UITextViewTextLengthChangeBlock)hb_textLengthChange{
    return objc_getAssociatedObject(self, kTextLengthChangeKey);
}

#pragma mark - **placeholderLabel

- (void)setPlaceholderLabel:(UILabel *)placeholderLabel{
    objc_setAssociatedObject(self, kPlaceholderLabelKey, placeholderLabel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (UILabel *)placeholderLabel{
    
    return objc_getAssociatedObject(self, kPlaceholderLabelKey);
}


#pragma mark - **placeholder

- (void)setHb_placeholder:(NSString *)hb_placeholder{
    objc_setAssociatedObject(self, kPlaceholderKey, hb_placeholder, OBJC_ASSOCIATION_COPY_NONATOMIC);
    if (hb_placeholder != nil && !self.placeholderLabel) {
        UILabel *label = [[UILabel alloc] init];
        label.textColor = self.hb_placeholderColor;
        [self addSubview:label];
        label.numberOfLines = 0;
        label.textAlignment = NSTextAlignmentLeft;
        label.hidden = self.hasText;
        objc_setAssociatedObject(self, kPlaceholderLabelKey, label, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    if (!self.placeholderLabel) return;
    [self setNeedsLayout];
}

- (NSString *)hb_placeholder{
    return objc_getAssociatedObject(self, kPlaceholderKey);
}


#pragma mark - **placeholderColor


- (void)setHb_placeholderColor:(UIColor *)hb_placeholderColor{
    objc_setAssociatedObject(self, kPlaceholderColorKey, hb_placeholderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    if (!self.placeholderLabel) return;
    self.placeholderLabel.textColor = hb_placeholderColor;
}

- (UIColor *)hb_placeholderColor{
    return objc_getAssociatedObject(self, kPlaceholderColorKey);
}

#pragma mark - **showTextCount

- (void)setShowTextCount:(BOOL)showTextCount{
    objc_setAssociatedObject(self, kShowTextCountKey, @(showTextCount), OBJC_ASSOCIATION_COPY_NONATOMIC);
    if (showTextCount && !self.textCountLabel) {
        UILabel *label = [[UILabel alloc] init];
        label.textColor = self.textCountDefaultColor;
        [self addSubview:label];
        label.numberOfLines = 1;
        label.font = self.textCountFont;
        label.textAlignment = NSTextAlignmentRight;
        objc_setAssociatedObject(self, kTextCountLabelKey, label, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    if (!self.textCountLabel) return;
    self.textCountLabel.hidden = !showTextCount;
    [self updateTextCountProperty];
    [self setNeedsLayout];
}

- (BOOL)showTextCount{
    return [objc_getAssociatedObject(self, kShowTextCountKey) boolValue];
}

#pragma mark - **textCountLabel

- (void)setTextCountLabel:(UILabel *)textCountLabel{
    objc_setAssociatedObject(self, kTextCountLabelKey, textCountLabel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (UILabel *)textCountLabel{
    return objc_getAssociatedObject(self, kTextCountLabelKey);
}

#pragma mark - **textCountDefaultColor

- (void)setTextCountDefaultColor:(UIColor *)textCountDefaultColor{
    objc_setAssociatedObject(self, kTextCountDefaultColorKey, textCountDefaultColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [self updateTextCountProperty];
}

- (UIColor *)textCountDefaultColor{
    return objc_getAssociatedObject(self, kTextCountDefaultColorKey);
}


#pragma mark - **textCountFullColor

- (void)setTextCountFullColor:(UIColor *)textCountFullColor{
    objc_setAssociatedObject(self, kTextCountFullColorKey, textCountFullColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [self updateTextCountProperty];
}

- (UIColor *)textCountFullColor{
    return objc_getAssociatedObject(self, kTextCountFullColorKey);
}

#pragma mark - **currentTextCount
- (void)setCurrentTextCount:(NSUInteger)currentTextCount{
    objc_setAssociatedObject(self, kCurrentTextCountKey, @(currentTextCount), OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSUInteger)currentTextCount{
    return [objc_getAssociatedObject(self, kCurrentTextCountKey) unsignedIntegerValue];
}

#pragma mark - **textCountFont

- (void)setTextCountFont:(UIFont *)textCountFont{
    objc_setAssociatedObject(self, kTextCountFontKey, textCountFont, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    if (!self.textCountLabel) return;
    self.textCountLabel.font = textCountFont;
    [self setNeedsLayout];
}

- (UIFont *)textCountFont{
    return objc_getAssociatedObject(self, kTextCountFontKey);
}

#pragma mark - **textCountRightMargin

- (void)setTextCountRightMargin:(CGFloat)textCountRightMargin{
    objc_setAssociatedObject(self, kTextCountRightMarginKey, @(textCountRightMargin), OBJC_ASSOCIATION_COPY_NONATOMIC);
    if (!self.textCountLabel) return;
    [self setNeedsLayout];
}

- (CGFloat)textCountRightMargin{
    return [objc_getAssociatedObject(self, kTextCountRightMarginKey) floatValue];
}

#pragma mark - **textCountBottomMargin
- (void)setTextCountBottomMargin:(CGFloat)textCountBottomMargin{
    objc_setAssociatedObject(self, kTextCountBottomMarginKey, @(textCountBottomMargin), OBJC_ASSOCIATION_COPY_NONATOMIC);
    if (!self.textCountLabel) return;
    [self setNeedsLayout];
}

- (CGFloat)textCountBottomMargin{
    return [objc_getAssociatedObject(self, kTextCountBottomMarginKey) floatValue];
}

#pragma mark - **autoInterceptMaxLength

- (void)setHb_autoInterceptMaxLength:(BOOL)hb_autoInterceptMaxLength{
    objc_setAssociatedObject(self, kAutoInterceptMaxLentghKey, @(hb_autoInterceptMaxLength), OBJC_ASSOCIATION_COPY_NONATOMIC);
    [self TextChange_Edit];
}

- (BOOL)hb_autoInterceptMaxLength{
    return [objc_getAssociatedObject(self, kAutoInterceptMaxLentghKey) boolValue];
}


#pragma mark - isInit

- (void)setIsInit:(BOOL)isInit{
    objc_setAssociatedObject(self, @selector(isInit), @(isInit), OBJC_ASSOCIATION_ASSIGN);
}

- (BOOL)isInit{
    return [objc_getAssociatedObject(self, @selector(isInit)) boolValue];
}

#pragma mark - 公开方法

- (void)hb_showEndEditToolView{
    CGFloat height = 40;
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, height)];
    view.backgroundColor = [UIColor whiteColor];
    CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
    
    UIView *line= [UIView new];
    line.backgroundColor = [UIColor lightGrayColor];
    line.frame = CGRectMake(0, 0, screenWidth, 0.5);
    [view addSubview:line];
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button addTarget:self action:@selector(resignFirstResponder) forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"完成" forState:UIControlStateNormal];
    button.titleLabel.font = [UIFont systemFontOfSize:16];
    [button setTitleColor:[UIColor colorWithRed:0 green:0 blue:0.8 alpha:1] forState:UIControlStateNormal];
    button.frame = CGRectMake(screenWidth - 64, 0, 64, height);
    [view addSubview:button];
    self.inputAccessoryView = view;
}

@end
